package sim;

import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import obj.Edge;
import obj.Node;
import obj.Path;
import ui.MainUI;
import ui.VehicleReportPanel;
import util.Util;

public class VehicleFactory implements Runnable, Observer {

	private VehicleComponent component;
	private Path path;
	private volatile boolean paused;
	private Vehicle prevVehicle;
	private int delay = 0;
	private double interval;
	private Node[][] nodesMatrix;
	public Map<Edge, Set<String>> carsInEdgesMap;

	public VehicleFactory(VehicleComponent comp, Path p, Node[][] matrix, Map<Edge, Set<String>> map) {

		component = comp;
		nodesMatrix = matrix;
		path = p;
		this.interval = (60 * 1000) / path.getVehiclePerMin();
		this.delay = (int) this.interval;
		this.carsInEdgesMap = map;

	}

	@Override
	public void run() {
		Timer panelTimer = new Timer();
		panelTimer.schedule(new TimerTask() {
			int count = 0;
			int sleep = 0;

			@Override
			public void run() {
				while (paused) {
					/* Wait here till simulation resumes */
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {

					}
				}
				sleep = updateDelay();
				try {
					Thread.sleep(Math.abs(sleep));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				/* generate vehicles */
				genarateVehicles(path, count);
				VehicleReportPanel.refreshTable(path);
				count++;
			}

		}, 0, delay);

	}

	public int updateDelay() {
		int sleep = 0;
		Random randomGenerator = new Random();
		sleep = Util.showRandomInteger((int) (this.interval - 2000), (int) (this.interval + 2000), randomGenerator);
		return sleep - this.delay;
	}

	public synchronized void genarateVehicles(Path p, int count) {

		Vehicle vehicle = new Car(p, p.getName() + "_" + count);

		component.add(vehicle);
		/* Set Lead vehicle */
		if (count > 0) {
			vehicle.setLeadVehicle(prevVehicle);
		}
		p.setVehiclesEntered(vehicle);
		prevVehicle = vehicle;
		Runnable r = new VehicleRunnable(vehicle, component, nodesMatrix, carsInEdgesMap);
		Thread t = new Thread(r);
		t.start();
		MainUI.registerSubscriber((VehicleRunnable) r);

	}

	@Override
	public void notify(boolean state) {
		this.paused = state;
	}

}
